# -*- coding: utf_8 -*-
# @Create   : 2021/9/1 11:14
# @Author   : yh
# @Remark   : 巡检任务server层
import logging
import os
import platform
import time

from mxsoftpy import Server
from mxsoftpy.exception import DataError, DBError

from db.common.VideoManage.VideoQuality.inspection_task import InspectionTaskDB
from db.common.Base.timed_task import TimedTaskDB
from model.common.VideoManage.VideoQuality.inspection_task import InspectionTaskModel, InspectionTaskSelectModel
from server.common.VideoManage.VideoQuality.inspection_plan import InspectionPlanServer
from server.common.Base.timed_task import TimedTaskServer
from utils.conf.mxconfig import MxConfig
from utils.public.export_execl import ExportExecl
from utils.public.params_method import pagination, update_select_params, \
    get_pagination_params
from utils.public.system_method import get_server_path


class InspectionTaskServer(Server):
    __db__ = InspectionTaskDB

    def create(self, **inspection_temp_task_model):
        """
        新增巡检任务
        :param inspection_temp_task_model: 巡检任务模型，详情见InspectionTaskModel类
        """
        inspection_temp_task = InspectionTaskModel(**inspection_temp_task_model)

        # 完成巡检任务的添加
        task_code = self.db.create(**inspection_temp_task.dict(exclude={'TestItems': ...}))

        # 完成巡检任务中检测项目添加
        try:
            assert self.db.create_or_update_items(task_code, inspection_temp_task.dict(include={'TestItems': ...})[
                'TestItems']), ''
        except Exception as e:
            InspectionTaskDB().delete(task_code)
            logging.error('添加一个临时巡检任务的检测项目时出错，已逻辑删除此任务，任务code: %s，错误详情：%s' % (task_code, str(e)))
            raise DataError('添加临时巡检任务失败')

        # 新增定时任务
        run_exe_name = 'python.exe' if platform.system() == 'Windows' else 'python.sh'  # 判断系统来选择不同执行名
        try:
            time_task_code = TimedTaskServer().create(name='临时巡检任务', runtype=2, RunExeName=run_exe_name, type=1,
                                                      RunPath=os.path.join(get_server_path(), 'python'),
                                                      starttime=inspection_temp_task_model['begin_time'],
                                                      parameter=os.path.join(get_server_path(), 'webexpress', 'python',
                                                                             'pyweb', 'view', 'common', 'VideoManage',
                                                                             'VideoQuality', 'task.py  %s' % task_code))
        except (DBError, AssertionError) as e:
            InspectionTaskDB().delete(task_code)
            logging.error('添加一个临时巡检任务到定时任务时出错，已逻辑删除此任务，任务code: %s，错误详情：%s' % (task_code, str(e)))
            raise DataError('添加临时巡检任务失败')

        InspectionTaskDB().update(task_code, **{'time_task_code': time_task_code})
        return task_code

    def _export_data(self, data):
        """
        转换成导出excl所需格式
        """
        data_dict = {
            "header": "巡视任务",
            "headline": {
                "id": "序号",
                "name": "任务信息",
                "inspection_plan_name": "任务来源",
                "begin_time": "开始时间",
                "end_time": "结束时间",
                "device_num": "设备数",
                "test_num": "检测项目",
                "normal_num": "正常项目",
                "fault_num": "故障项目",
                "failed_num": "检测失败",
                "principal": "负责人",
            },
            "data": data
        }
        file_name = "task_" + str(int(time.time())) + ".xlsx"
        return data_dict, file_name

    def select(self, **kwargs):
        """
        列表展示所有巡检任务
        :param kwargs: 查询及分页参数，查询参数字段见InspectionTaskSelectModel类
        """

        export_code = kwargs.get('export_code')

        select_model = InspectionTaskSelectModel(**kwargs)
        param_dict = {
            'begin_time__gte': select_model.begin_time,
            'begin_time__lte': select_model.end_time,
            'end_time__gte': select_model.begin_time,
            'end_time__lte': select_model.end_time,
            'name__like': '*%s*' % select_model.name,
            'state': 1 if select_model.task_state.value and not select_model.state else select_model.state,
            'task_state': select_model.task_state.value,
            'inspection_plan_code': select_model.plan_code,
            'default_expression': '((0 and 1) or (2 and 3)) and 4 and 5 and 6 and 7',  # 查询字段的逻辑关系
        }

        total, data = self.db.select(**update_select_params(param_dict, kwargs))
        # 添加序号
        i = 0
        for value in data['data']:
            i += 1
            value['id'] = i

        # 导出Excel
        if export_code == "1":
            data_dict, file_name = self._export_data(data['data'])
            path = MxConfig.TMP_DIR + file_name
            execl_path = os.sep + "tmp" + os.sep + file_name
            if data_dict["data"]:
                try:
                    ExportExecl().data_process(data_dict)(path)
                    logging.info("成功导出excle")
                    return {'execl_path': execl_path}
                except DataError:
                    logging.error("导出excle出错")
                    raise DataError("导出excle出错")

            else:
                raise DataError("数据为空")

        return pagination(data, get_pagination_params(kwargs), total)

    def delete(self, task_code: str) -> str:
        """
        删除巡检任务
        :param task_code: 要删除的任务code
        """
        task_items = self.db.retrieve(task_code)

        try:
            self.db.delete(task_code)  # 删除巡检任务
        except DBError as e:
            logging.error('删除巡检任务时：更新任务的state失败, 巡检任务code：%s，错误详情：%s' % (task_code, str(e)))
            raise DataError('删除巡检任务失败')

        try:
            TimedTaskDB().delete(task_items['time_task_code'], **{'state': 0})  # 删除定时任务
        except DataError as e:
            logging.error('删除巡检任务时：删除定时任务并同步到mq失败，巡检任务code：%s，定时任务code：%s， 错误详情：%s' % (
                task_code, task_items['time_task_code'], str(e)))
            self.db.update(task_code, **{'state': 1})  # 回滚删除操作

            raise DataError('删除巡检任务失败')

        return task_code


class InspectionSourceServer(Server):

    def select(self, name: str):
        """
        任务来源联想查询
        :param name: 要模糊匹配的名称
        """
        if name:
            select_data = InspectionPlanServer().select(name=name)

            # TODO 或许不同临时任务也应有不同编号，以后再加上相应逻辑
            if '临时任务'.find(name) != -1:
                select_data['data'].append({'name': '临时任务', 'plan_code': '0'})

            return select_data
        else:
            return []
